
#include <ESP8266WiFiMulti.h>

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

#include <ArduinoJson.h>

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>

#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#include <Ticker.h>

ESP8266WiFiMulti wifiMulti;

// WiFi connect timeout per AP. Increase when connecting takes longer.
const uint32_t connectTimeoutMs = 5000;

#if defined(ARDUINO_FEATHER_ESP32) // Feather Huzzah32
  #define TFT_CS         14
  #define TFT_RST        15
  #define TFT_DC         32

#elif defined(ESP8266)
  #define TFT_CS         4
  #define TFT_RST        16
  #define TFT_DC         5

#else
  // For the breakout board, you can use any 2 or 3 pins.
  // These pins will also work for the 1.8" TFT shield.
  #define TFT_CS        10
  #define TFT_RST        9 // Or set to -1 and connect to Arduino RESET pin
  #define TFT_DC         8
#endif

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

#define CLK 0
#define DIO 2
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ CLK, /* data=*/ DIO, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display

// 打印调试
#define Serial_P true
#define Serial_I true

void updateInfo();
int updateCount = 0;  // 定时器 当前次数
int requestStatu = 0; // 请求状态值 0 准备请求；1 请求完成；200 请求成功；3网络已连接； -1 请求失败完成；-2请求未开始；-3网络未连接
int httpCode = 0;     // 请求结果值

Ticker timer1;

// 北京时间URL
const char* beijingTimeUrl = "https://bjtime.org.cn/bjtime.php?timeZone=8";
const char* timeCusUrl = "http://110.41.40.83:7997/app/login/tinfo?token=time";
// 高德天气api 来自中国气象局 实况天气 每日300000次
const char* weatherUrl = "http://restapi.amap.com/v3/weather/weatherInfo?key=11792e0ede8799a1f8e67d0ac4fa96a9&city=110000&output=JSON&extensions=";

int year  = 0; 
int month = 0;
int day   = 0; 
int hour  = 0;
int minute = 0;
int second = 0;
int weekday = 0;
unsigned long beijingTimestamp = 0;
int timeURLType = 0;


// 实况天气结构体
struct WeatherLives {
  String province;          //省份名
  String city;              //城市
  String adcode;            //区域编码
  String weather;           //天气现象
  String temperature;       //实时气温，单位：摄氏度
  String winddirection;     //风向描述
  String windpower;         //风力级别，单位：级
  String humidity;          //空气湿度
  String reporttime;        //数据发布的时间
  String temperature_float; //实时气温，单位：摄氏度
  String humidity_float;    //空气湿度
};

// 预报天气结构体
struct WeatherForecasts {
  String province;      //省份名
  String city;          //城市
  String adcode;        //区域编码
  String reporttime;    //数据发布的时间

  String date;            //日期
  String week;            //星期几
  String dayweather;      //白天天气现象
  String nightweather;    //晚上天气现象
  String daytemp;         //白天温度
  String nighttemp;       //晚上温度
  String daywind;         //白天风向
  String nightwind;       //晚上风向
  String daypower;        //白天风力
  String nightpower;      //晚上风力
  String daytemp_float;   //白天温度 float
  String nighttemp_float; //晚上温度 float
};

// 天气实况信息
String weatherLiveInfo = "";
// 天气预报信息
String weatherForecastsInfo = "";

// 实况天气数据
struct WeatherLives wLive;
// 预报天气数据
struct WeatherForecasts wForecast[4];

#define D_FMQ 12  //蜂鸣器
#define D_LED 15  //二极管
int dggd = 0; // 光敏二极管

unsigned long drawTime = 0;

void setup() {
  if (Serial_I) {
    Serial.begin(9600);
  }
  
  initDisplay();      //初始化显示
  multiWificonfig();  //初始化WiFi
  initDevice();       //初始化板子硬件
  requestWeatherInfo(); //请求天气信息
  requestTimeInfo(2);   // 请求时间信息
  
  timer1.attach(1, updateInfo); //启动定时器
}

void loop() {
  
  if (second == 0) {
    if (drawTime == 0) {
      displayTime(); // 每分钟 第0秒 更新显示时间
      drawTime = 1200;
      if (Serial_P) {
        Serial.println("刷新显示");
      }
    }
  }else {
    drawTime = 0;
  }
  if ((hour % 6 == 0) && minute == 2 && second == 30) {
    // 每天 0 6 12 18 点 第 59 分 12 秒  请求时间信息
    requestWeatherInfo(); //请求天气信息
    requestTimeInfo(2);   // 请求时间信息
  }else if (second == 30) { // 测试内容
    
  }else {
    
  }

}

// 每秒更新
void updateInfo() {
  updateCount++;  //计数++
  beijingTimestamp++; // 时间戳++
  dggd = analogRead(A0);  // 光敏电阻读取数值更新
  showWeatherData();
  timestamp_to_beijing(beijingTimestamp); // 解析时间戳
}

void showWeatherData() {

  if (second %20 >= 10) {
    // 第一行 -------- 
    String c1 = "周" + getWeekdayString(weekday) + " " + String(second) + " 光：" + String(dggd);
    // 第二行 -------- 实况天气
    String c2 = lineContent(true, wLive, wForecast[0]);
    // 第二行 --------
    // 第三行 -------- 预报天气
    String c3 = "明天 " + lineContent(false, wLive, wForecast[1]);
    // 第三行 --------
    oledDisplayData(c1, c2, c3, "");
  }else {

    String hourS = padZeros(hour, 2);
    String minuteS = padZeros(minute, 2);
    String t = (second % 2 == 1) ? " " : ":";
    u8g2.firstPage();
    do {
      u8g2.setFont(u8g2_font_logisoso38_tn);
      u8g2.drawStr(3,63, hourS.c_str());
      u8g2.drawStr(55,63, t.c_str());
      u8g2.drawStr(75,63, minuteS.c_str());
    } while ( u8g2.nextPage() );
  }
}

// 显示 oled
void oledDisplayData(String line1, String line2, String line3, String line4) {
  
  u8g2.clearBuffer();	
  u8g2.setFont(u8g2_font_wqy16_t_gb2312); //设置字体
	
  // 第一行 -------- 
  showLine(line1, 1);
  // 第一行 --------

  // 第二行 -------- 
  showLine(line2, 2);
  // 第二行 --------

  // 第三行 --------
  showLine(line3, 3);
  // 第三行 --------

  // 第四行 --------
  showLine(line4, 4);
  // 第四行 --------

  u8g2.sendBuffer();
}
// 组装显示内容
String lineContent(bool isLive, struct WeatherLives live, struct WeatherForecasts forecast) {
  
  String weather = isLive ? live.weather : forecast.dayweather;
  weather = weather + ((weather.length() == 1) ? ( "天 ") : " " );
  String temperature = isLive ? live.temperature : forecast.nighttemp;
  String winddirection = isLive ? live.winddirection : forecast.daywind;
  String windpower = isLive ? live.windpower : forecast.daypower;
  return isLive ? (weather + temperature + "°C " + winddirection + "风") : (weather + temperature + "°C");
}

// 显示一行的内容
// content：内容 ： line： 第几行
void showLine(String content, int line) {
  
  int y = 14 + (line-1)*16;
  u8g2.setCursor(0, y);
  u8g2.print(content);
}

// 获取天气信息
void requestWeatherInfo() {
  
  requestWeatherMsg(1);
  requestWeatherMsg(2);
}

// extensions：base实况天气；all预报天气
void requestWeatherMsg (int type) {
  String extensions = "base";
  if (type == 2) {
    extensions = "all";
  }
  String weatherURL = weatherUrl + extensions;  // 拼接天气数据url
  String weather = getHttpPayload(weatherURL);
  analysisWeatherInfo(weather, type);

  if (Serial_P) {
    Serial.println(weather);
  }
}

// 解析天气数据
void analysisWeatherInfo(String weather, int type) {
  JsonDocument weatherDocument;
  deserializeJson(weatherDocument, weather);

  String status = weatherDocument["status"];
  if (status.toInt() == 1) {// 请求成功
    int infocode = weatherDocument["infocode"];
    if (type == 1) { //实况
      // 实况天气数据信息
      JsonArray lives = weatherDocument[String("lives")].as<JsonArray>();
      // 解析实况天气数据
      struct WeatherLives live;
      live = creatLives(lives[0]);
      wLive = live;
      printLnLives(live);   //打印天气信息
    }else if ( type == 2 ) {
        // 预报天气数据信息
        JsonArray forecasts = weatherDocument[String("forecasts")].as<JsonArray>();
        // 解析预报天气数据
        String allKey[3] = {"province", "city", "reporttime"};
        String allDes[3] = {"省份名", "城市", "数据发布的时间"};

        String province   = forecasts[0][String("province")];
        String city       = forecasts[0][String("city")];
        String adcode     = forecasts[0][String("adcode")];
        String reporttime = forecasts[0][String("reporttime")];
        // 预报数据list结构，元素cast,按顺序为当天、第二天、第三天的预报数据
        String castsString = forecasts[0][String("casts")];
        DynamicJsonDocument castsDocument(2048);
        deserializeJson(castsDocument, castsString);

        for (int i = 0; i < 4; i++) {

          struct WeatherForecasts forecast;
          JsonObject forecastObj = castsDocument[i];
          forecastObj[String("province")]   = province;
          forecastObj[String("city")]       = city;
          forecastObj[String("adcode")]     = adcode;
          forecastObj[String("reporttime")] = reporttime;
          forecast = creatForecasts(forecastObj);
          
          wForecast[i] = forecast;
          printLnForecasts(wForecast[i]); //打印天气信息
        }
    }
  }else { // 请求失败

  }
}


// 获取时间信息
String requestTimeInfo(int type) {
  timeURLType = type;

  String timeInfo = "";
  if (type == 1) {
    timeInfo = getHttpPayload(beijingTimeUrl);
  }else if (type == 2) {
    timeInfo = getHttpPayload(timeCusUrl);
  }

  // 请求失败 切换 另一侧数据源
  if (timeInfo.length() == 0) {
    if (Serial_P) {
      Serial.println("请求失败 切换到对侧数据源");
    }
    delay(5000);
    if (type == 1) {
      return requestTimeInfo(2);
    }else if (type == 2) {
      return requestTimeInfo(1);
    }else {
      return requestTimeInfo(1);
    }
  }else {
    if (Serial_P) {
      Serial.println("请求成功 刷新时间显示");
      Serial.println(timeInfo);
    }
    // 请求成功 刷新时间显示
    timeString_to_beijing(timeInfo, type); // 解析到时间
    displayTime();  //显示时间
  }
  
  return timeInfo;
}

// 请求接口数据
String getHttpPayload(String url) {

  int requestStatu = 0; // 准备请求
  
  String requestInfo = "http ready to request";
  if (Serial_P) {
    Serial.println(">> http ready to request");
  }
  if ((wifiMulti.run() == WL_CONNECTED)) { // 连接Wi-Fi成功
    requestStatu = 3; // Wi-Fi已连接
    //创建 HTTPClient 对象
    HTTPClient httpsClient;
    WiFiClient* client;

    if (is_prefix(url.c_str(), "https")) {
      BearSSL::WiFiClientSecure wifiClient;
      wifiClient.setInsecure();
      client = &wifiClient;  
      if (Serial_P) {
        Serial.println(">> http begin request wifiClient is WiFiClientSecure");
      }
    }else {
      WiFiClient wifiClient;
      client = &wifiClient;  
      if (Serial_P) {
        Serial.println(">> http begin request wifiClient is WiFiClient");
      }
    }

    if ( httpsClient.begin(*client, url) ) {
        if (Serial_P) {
          Serial.println(">> http get request：" + url);
        }
        // 启动连接并发送HTTP头
        httpCode = httpsClient.GET();
        
        if (httpCode > 0) {
          requestStatu = 1; // 请求完成
          if (httpCode == HTTP_CODE_OK) {
            requestStatu = 200; // 请求成功
            String payload = httpsClient.getString();
            requestInfo = payload;
            // 返回payload
            return payload;
          }else {
            String payload = httpsClient.getString();

            if (Serial_P) {
              Serial.println(">> http get httpCode：" + httpCode);
              Serial.println(">> http get payload：" + payload);
            }
            requestInfo = "http code not ok";
          }
        }else {
          requestStatu = -1; // 请求失败完成
          if (Serial_P) {
            Serial.printf("http get failed, error:%s\n", httpsClient.errorToString(httpCode).c_str());
            Serial.println("");
          }
        }
        httpsClient.end();
        if (Serial_P) {
          Serial.println(requestInfo);
          Serial.println(requestStatu);
          Serial.println(httpCode);
        }
      }else {
        requestStatu = -2;//请求未开始
        if (Serial_P) {
          Serial.println("http request failure");
        }
      }
  }else {
    requestInfo = "wifi is not connected";
    requestStatu = -3; // 网络未链接
  }
  if (Serial_P) {
    Serial.println(requestInfo);
    Serial.println(requestStatu);
    Serial.println("http end request info");
  }
  return "";
}

void initDisplay() {
  tft.init(240, 280);   // Init ST7789 280x240
  tft.setRotation(3);   // 旋转屏幕至合适的方向
  
  if (Serial_P) {
    Serial.println(F("initDisplay"));
  }

  tft.fillScreen(ST77XX_BLACK);
  tft.setTextWrap(false);
  displayPrintlnFromXY("init display", 2, 0, 25);

  initOledDisplay();
}

// 初始化 0.96 Oloed 显示屏
void initOledDisplay() {
  u8g2.begin();
  u8g2.enableUTF8Print();     //enable UTF8
  u8g2.setFont(u8g2_font_wqy16_t_gb2312); //设置字体
  oledDisplayData("正在连接 WiFi...", "", "", "" );
}

// 初始化Wi-Fi链接
void multiWificonfig() {
  // Don't save WiFi configuration in flash - optional
  WiFi.persistent(false);
  
  // Set WiFi to station mode
  WiFi.mode(WIFI_STA);

  // Register multi WiFi networks
  wifiMulti.addAP("ChinaNet-QbGx", "esfhkwihzd638h");
  wifiMulti.addAP("wifi-wjh6", "987987987oop");
  wifiMulti.addAP("iPhone X", "987987987");

  displayPrintln("WiFi is connecting", 2);
  displayPrintln(" ", 1);
  String c = "";
  while(wifiMulti.run(connectTimeoutMs) != WL_CONNECTED) {
    // Maintain WiFi connection
    c = c + ".";
    if (c.length() >= 6) {
      c = ".";
    }
    displayPrint(c.c_str(), 1);
    oledDisplayData("正在连接 WiFi...", c, "", "" );
    delay(1000);
  }
  displayPrintln(".", 1);
  displayPrintln("WiFi connected: ", 2);
  displayPrintln(WiFi.SSID().c_str(), 2);
  displayPrintln("IP address: ", 2);
  displayPrintln(WiFi.localIP().toString().c_str(), 2);
  oledDisplayData("正在连接 WiFi...", "连接 WiFi 成功", WiFi.SSID(), WiFi.localIP().toString() );
}

void initDevice() {
  pinMode(BUILTIN_LED, OUTPUT); //板载 LED
  pinMode(D_LED, OUTPUT); // 焊接 LED
  pinMode(D_FMQ, OUTPUT); // 焊接 蜂鸣器

  digitalWrite(BUILTIN_LED, LOW);
  digitalWrite(15, LOW);
  digitalWrite(13, LOW);
}

// 蜂鸣器 响几次
void fmqAction(int count) {
  
  int i = 0;
  do {
    digitalWrite(D_FMQ, HIGH);
    delay(100);
    digitalWrite(D_FMQ, LOW);
    delay(500);
    i++;
  }while(i<count);
  
}

// LED 闪烁
void ledAction(int count){
  int i = 0;
  do {
    digitalWrite(D_LED, HIGH);
    delay(500);
    digitalWrite(D_LED, LOW);
    delay(500);
    i++;
  }while(i<count);
}

// 屏幕显示 and 打印 ——————————————————————————————————————————————————————————————————
// 换行打印
void displayPrintlnFromXY(const char str[], int size, int corx, int cory) {
  if (corx >= 0 && cory >= 0) {
    tft.setCursor(corx, cory);
  }
  displayPrintln(str, size);
}

// 换行打印
void displayPrintln(const char str[], int size) {
  baseDisplayPrint(str, size, true);
}
// 不换行打印
void displayPrint(const char str[], int size) {
  baseDisplayPrint(str, size, false);
}
// 打印 字符
void baseDisplayPrint(const char str[], int size, bool line) {
  tft.setTextColor(ST77XX_WHITE);
  tft.setTextSize(size);
  if(line) {
    tft.println(str);
  }else {
    tft.print(str);
  }
  if (Serial_P) {
    if(line) {
      Serial.println(str);
    }else {
      Serial.print(str);
    }
  }
}

// 字符串前缀判断
int is_prefix(const char *str, const char *prefix) {
    return strncmp(str, prefix, strlen(prefix)) == 0;
}
// 时间字符串转换时间
void timeString_to_beijing(String timeInfo, int type){
  
  JsonDocument timeDocument;
  deserializeJson(timeDocument, timeInfo);
  if (type == 1) {
    String timeString = timeDocument["times"].as<String>();
    unsigned long times = 0;
    if (timeString.length() == 13) {
      times = timeString.substring(0,10).toInt();
    }
    beijingTimestamp = times;
  }else if (type == 2) {
    
    JsonObject obj = timeDocument["obj"];
    unsigned long timespe = obj["timespe"];
    beijingTimestamp = timespe;
  }
  if (Serial_P) {
      Serial.print("beijingTimestamp is : ");
      Serial.println(beijingTimestamp);
    } 
  timestamp_to_beijing(beijingTimestamp);
}

// 更新显示时间
void displayTime() {

  String monthS = padZeros(month, 2);
  String dayS = padZeros(day, 2);
  String hourS = padZeros(hour, 2);
  String minuteS = padZeros(minute, 2);
  
  String ymd = String(year) + "-" + monthS + "-" + dayS;
  String sf = hourS + ":" + minuteS;
  tft.fillScreen(ST77XX_BLACK);
  displayPrintlnFromXY(ymd.c_str(), 4, 25, 2);
  displayPrintlnFromXY(sf.c_str(), 5, 60, 39);
}

// 时间戳转换北京时间
void timestamp_to_beijing(int timestamp) {
  if (Serial_P) {
    Serial.println(timestamp);
  }
  timestamp += 8 * 3600 + 10; // 加上8小时的秒数（8 * 3600 = 28800）
  time_t t = timestamp;
  // 将时间戳转换为tm结构
  struct tm *timeinfo;
  timeinfo = localtime(&t);

  year = timeinfo->tm_year + 1900;
  month = timeinfo->tm_mon + 1;
  day = timeinfo->tm_mday;
  hour = timeinfo->tm_hour;
  minute = timeinfo->tm_min;
  second = timeinfo->tm_sec;
  weekday = timeinfo->tm_wday;
  if (Serial_P) {
    Serial.println(""); 
    Serial.print(year);
    Serial.print("-");
    Serial.print(month);
    Serial.print("-");
    Serial.print(day);
    Serial.print(" ");
    Serial.print(hour);
    Serial.print(":");
    Serial.print(minute);
    Serial.print(":");
    Serial.print(second);
    Serial.println(""); 
  }
}

// 补零函数定义  
String padZeros(int number, int width) {  
  // 将整数转换为字符串  
  String str = String(number);  
    
  // 计算需要补零的数量  
  int zerosToPad = width - str.length();  
    
  // 如果需要补零，则生成补零字符串  
  if (zerosToPad > 0) {  
    String zeros = "";  
    for (int i = 0; i < zerosToPad; i++) {  
      zeros += '0';  
    }  
    str = zeros + str;  
  }  
    
  return str;  
}


// 构造实况天气数据
WeatherLives creatLives(JsonObject lives) {
  
  struct WeatherLives live;
  live.province           = lives[String("province")].as<String>();
  live.city               = lives[String("city")].as<String>();
  live.adcode             = lives[String("adcode")].as<String>();
  live.weather            = lives[String("weather")].as<String>();
  live.temperature        = lives[String("temperature")].as<String>();
  live.winddirection      = lives[String("winddirection")].as<String>();
  live.windpower          = lives[String("windpower")].as<String>();
  live.humidity           = lives[String("humidity")].as<String>();
  live.reporttime         = lives[String("reporttime")].as<String>();
  live.temperature_float  = lives[String("temperature_float")].as<String>();
  live.humidity_float     = lives[String("humidity_float")].as<String>();
  return live;
}

// 构造预报天气数据
WeatherForecasts creatForecasts(JsonObject forecasts) {
  
  struct WeatherForecasts forecast;
  forecast.province        = forecasts[String("province")].as<String>();
  forecast.city            = forecasts[String("city")].as<String>();
  forecast.adcode          = forecasts[String("adcode")].as<String>();
  forecast.reporttime      = forecasts[String("reporttime")].as<String>();

  forecast.date            = forecasts[String("date")].as<String>();
  forecast.week            = forecasts[String("week")].as<String>();
  forecast.dayweather      = forecasts[String("dayweather")].as<String>();
  forecast.nightweather    = forecasts[String("nightweather")].as<String>();
  forecast.daytemp         = forecasts[String("daytemp")].as<String>();
  forecast.nighttemp       = forecasts[String("nighttemp")].as<String>();
  forecast.daywind         = forecasts[String("daywind")].as<String>();
  forecast.nightwind       = forecasts[String("nightwind")].as<String>();
  forecast.daypower        = forecasts[String("daypower")].as<String>();
  forecast.nightpower      = forecasts[String("nightpower")].as<String>();
  forecast.daytemp_float   = forecasts[String("daytemp_float")].as<String>();
  forecast.nighttemp_float = forecasts[String("nighttemp_float")].as<String>();
  return forecast;
}

String getWeekdayString(int day) {  
  // 检查输入是否在有效范围内（1到7）  
  if (day < 1 || day > 7) {  
    return "Invalid day";  
  }  
  
  // 使用数组存储星期几的名称  
  const char* weekdays[] = {  
    "日",  
    "一",  
    "二",  
    "三",  
    "四",  
    "五",  
    "六"  
  };  
  
  // 返回对应的星期几名称  
  return String(weekdays[day - 1]);  
} 


// 打印实况天气数据
void printLnLives( struct WeatherLives live) {
  
  if (Serial_P) {
    weatherLiveInfo = live.city + "天气:" + live.weather + "实时气温:" + live.temperature + "°C" + live.winddirection + "风" + live.windpower + "级 " + "空气湿度:" + live.humidity;
    Serial.printf("省份名:%s ", live.province);
    Serial.printf("城市:%s ", live.city);
    Serial.printf("区域编码:%s ", live.adcode);
    Serial.printf("天气现象:%s ", live.weather);
    Serial.printf("实时气温，单位：摄氏度:%s ", live.temperature);
    Serial.printf("风向描述:%s ", live.winddirection);
    Serial.printf("风力级别，单位：级:%s ", live.windpower);
    Serial.printf("空气湿度:%s ", live.humidity);
    Serial.print("数据发布的时间:");Serial.print(live.reporttime);Serial.print(" ");
    Serial.printf("实时气温，单位：摄氏度:%s ", live.temperature_float);
    Serial.printf("空气湿度:%s ", live.humidity_float);
    Serial.println("");
  }
}

// 打印预报天气数据
void printLnForecasts( struct WeatherForecasts forecast) {
  
  if (Serial_P) {
    weatherForecastsInfo = 
    Serial.printf("省份名:%s ", forecast.province);
    Serial.printf("城市:%s ", forecast.city);
    Serial.printf("区域编码:%s ", forecast.adcode);
    Serial.print("数据发布的时间:");Serial.print(forecast.reporttime);Serial.print(" ");

    Serial.printf("日期:%s ", forecast.date);
    Serial.printf("星期几:%s ", forecast.week);
    Serial.printf("白天天气现象:%s ", forecast.dayweather);
    Serial.printf("晚上天气现象:%s ", forecast.nightweather);
    Serial.printf("白天温度:%s ", forecast.daytemp);
    Serial.printf("晚上温度:%s ", forecast.nighttemp);
    Serial.printf("白天风向:%s ", forecast.daywind);
    Serial.printf("晚上风向:%s ", forecast.nightwind);
    Serial.printf("白天风力:%s ", forecast.daypower);
    Serial.printf("晚上风力:%s ", forecast.nightpower);
    Serial.printf("白天温度:%s ", forecast.daytemp_float);
    Serial.printf("晚上温度:%s ", forecast.nighttemp_float);
    Serial.println("");
  }
}

